/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


/*************************************************************************
 * File: codec.hpp
 *************************************************************************
 *\author: starlove
 *************************************************************************/

#ifndef __CC_PYTHON_CODEC_H__
#define __CC_PYTHON_CODEC_H__

#include "platform.hpp"
#include "buffer.hpp"
#include "string.hpp"
#include <python_import_macro.h>
#include <typeinfo>

NS_CCPY_BEGIN

#define __BUFFER_SIZE__ (1024 * 96)
#define __CODEC_BUFFER_SIZE__ 512

    typedef const char *STR;

	class IData
	{
		public:
			virtual ~IData() {};
			virtual char GetDataType() = 0;
			virtual bool Load(CBufferReader *) = 0;
			virtual bool Dump(IAutoExpandBuffer *) = 0;
	};

    enum DATA_TP
    {
        DTP_NULL	= 0,
        DTP_INT		= 1,
        DTP_INT64	= 2,
        DTP_STR		= 3,
        DTP_FLOAT	= 4,
        DTP_BOOL	= 5,
        DTP_DOUBLE	= 6,
        DTP_MAP		= 7,
        DTP_LIST	= 8,
        DTP_BUFFER	= 9,
        DTP_PBUFFER	= 10,
        DTP_MEMORY	= 11,
        DTP_PYSTR	= 12
    };

    inline unsigned int GetDataTypeSize(char tp)
    {
        switch (tp)
        {
            case DTP_INT:
                return sizeof(int);
            case DTP_INT64:
                return sizeof(INT64);
            case DTP_FLOAT:
                return sizeof(float);
            case DTP_BOOL:
                return sizeof(bool);
            case DTP_DOUBLE:
                return sizeof(double);
            case DTP_STR:
                return sizeof(char *);
            default:
                return sizeof(void *);
        }
    };

    typedef CAutoExpandBuffer<__CODEC_BUFFER_SIZE__> CODEC_BUFFER;

#pragma pack(1)

    typedef struct __DATA_HEADER
    {
        char tp;
        unsigned int size;

    } DATA_HEADER, *LPDATA_HEADER;

    typedef struct __KEYVALUE_DATA_HEADER
    {
        DATA_HEADER key;
        DATA_HEADER value;
    } KEYVALUE_DATA_HEADER, *LPKEYVALUE_DATA_HEADER;

    typedef struct __DATA_NODE
    {
        DATA_HEADER header;
        const void *data;
        int buffer_offset;

    } DATA_NODE, *LPDATA_NODE;

    typedef struct __KEYVALUE_DATA_NODE
    {
        KEYVALUE_DATA_HEADER header;
        const void *data;
        int buffer_offset;

    } KEYVALUE_DATA_NODE, *LPKEYVALUE_DATA_NODE;

    typedef struct __HASH_KEY
    {
        char tp;
        int i_key;
        char str_key[255];

		bool operator==(const __HASH_KEY& __x) const
		{
			if (__x.tp != tp)
				return false;
            switch (tp)
            {
                case DTP_STR:
                    //return std::priv::__stl_hash_string(__x.str_key) == std::priv::__stl_hash_string(str_key);
					return strcmp(__x.str_key, str_key) == 0;
                default:
                    return __x.i_key == i_key;
            }
            return false;
		}
    } HASH_KEY, *LPHASH_KEY;

    struct HASH
    {
        size_t operator()(const HASH_KEY& key) const
        {
        	switch (key.tp)
            {
                case DTP_STR:
					{
						const unsigned char *p = (const unsigned char *)key.str_key;
						size_t hash_code = 0;
						for (size_t n = strlen(key.str_key); 0 < n; --n)
							hash_code += *p++;
						return hash_code;
					}
                    //return std::priv::__stl_hash_string(key.str_key);
                default:
                    return static_cast<size_t>(key.i_key);
            }
            return 0;
        }
    };

#pragma pack()

    class IEncoder
    {
        public:
            virtual ~IEncoder() {};
			/// target data >> encodedstream
            virtual bool Encode(IAutoExpandBuffer *, void *) = 0;
			/// target data >> c data
            virtual bool Encode(IData *, void *) = 0;
    };

    class IDecoder
    {
        public:
            virtual ~IDecoder() {};
			/// encodedstream >> target data
            virtual bool Decode(CBufferReader *, void *) = 0;
			/// c data >> target data
            virtual bool Decode(IData *, void *) = 0;
    };

    typedef IEncoder *LPIEncoder;
    typedef IDecoder *LPIDecoder;

    class ICodec
    {
        public:
            virtual LPIEncoder GetEncoder() = 0;
            virtual LPIDecoder GetDecoder() = 0;
    };
	
NS_CCPY_END

#endif	//!__CC_PYTHON_CODEC_H__